#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <string>
#include "Thread.hpp"
using namespace std;

const static int defaultnum=5;

struct ThreadData
{
    string name;
    pthread_t tid;
};

template<class T>
class ThreadBool
{
public:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }

    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }

    void Wakeup()
    {
        pthread_cond_signal(&cond_);
    }

    void ThreadSleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }

    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }

    // string GetName(pthread_t tid)
    // {
    //     for(auto &ch :threads_)
    //     {
    //         if(ch.tid==tid)
    //         {
    //             return ch.name;
    //         }
    //     }
    //     return "None";
    // }

public:
    ThreadBool(int cap=defaultnum)
    // :cap_(cap),threads_(cap)  
    :cap_(cap)  //封装后的
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }
    
    static void* HandlerTask(void* args)//不传this指针的话，会使得进程无法访问非静态成员变量，函数
    {
        ThreadBool<T>* tb=static_cast<ThreadBool<T>*>(args);
        // string name=tb->GetName(pthread_self());

        while(1)
        {
            tb->Lock();
            while(tb->IsQueueEmpty())
            {
                tb->ThreadSleep();
            }
            T t=tb->Pop();//领任务
            tb->Unlock();
            t();//运算，并发

            cout/*<< name*/<<"run ,"<<"result "<<t.GetResult()<<endl;
        }
    }

    void Push(const T& in)
    {
        Lock();//之所以要上锁是因为，插入是访问queue，queue是临界资源
        tasks_.push(in);
       
        Wakeup();//唤醒操作不是原子的；
        Unlock();
    }

    T Pop()
    {
        T out=tasks_.front();
        tasks_.pop();
        return out;
    }

    // void start()
    // {
    //     for(int i=0;i<cap_;i++)
    //     {
    //         threads_[i].name="thread-"+to_string(i+1);
    //         pthread_create(&(threads_[i].tid),nullptr,HandlerTask,this);
    //     }
    // }

    void start()
    {
        for(int i=0;i<cap_;i++)
        {
            threads_.push_back(Thread(HandlerTask,this));
            threads_[i].Run();//运行起来
        }
    }

    ~ThreadBool()
    {
        for(auto&t:threads_)
        {
            t.join();//线程销毁
        }

        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

    static ThreadBool<T>* GetInstance()//只有一份
    {
        if(tb_==nullptr)//前面的线程已经创建资源成功了，那就没必要在排队了
        {
            pthread_mutex_lock(&lock_);//多个线程竞争一个，但是只创建一份，所以上锁
            if(tb_==nullptr)
            {
                cout<<"懒汉模式创建，只有一份"<<endl;
                tb_=new ThreadBool<T>();
            }

            pthread_mutex_unlock(&lock_);
        }
        return tb_;
    }

    ThreadBool(const ThreadBool<T>& ) =delete;
    const ThreadBool<T>& operator=(const ThreadBool<T>&) =delete;//禁止掉拷贝，赋值；

private:
    // vector<ThreadData> threads_;
    vector<Thread> threads_;  //封装的线程，作为
    queue<T> tasks_;

    int cap_;

    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    //懒汉模式
    static pthread_mutex_t lock_;
    static ThreadBool<T>* tb_;
};

template <class T>
pthread_mutex_t ThreadBool<T>::lock_=PTHREAD_MUTEX_INITIALIZER; 

template <class T>
ThreadBool<T>* ThreadBool<T>::tb_=nullptr;
